﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Data.OleDb;
using System.Collections;

namespace FlyShop
{
    public partial class FrmCadastroVoo : Form
    {

        // Indica se o form está em modo de edição
        public bool edicao = false;

        // Código do registro a ser alterado
        public int codVoo = 0;

        // Indica a quantidade de assentos suportada pela aeronave selecionada
        int qntAssentosAeronaveSelecionada = 0;

        OleDbConnection conexao;
        OleDbCommand comando;
        OleDbDataReader dr;
        OleDbParameter pCod, pNome, pValor, pAssentos, pTotalAssentos, pDataPartida, pDataChegada, pCodAeronave, pCodAeroportoPartida, pCodAeroportoChegada;

        String strConexao = "Provider=MSDAORA.1;Data Source=localhost;Persist Security Info=True;User ID=pi;Password=pi";

        String sqlConsultaVoo = "select v.cod_voo, v.nome, v.valor, v.assentos_disponiveis, arnv.cod_aeronave, arnv.assentos as total_assentos_aeronave, v.data_partida, v.data_chegada, v.cod_aeroporto_partida, v.cod_aeroporto_chegada, cp.cod_cidade as cod_cidade_partida, cp.uf as uf_cidade_partida, cc.cod_cidade as cod_cidade_chegada, cc.uf as uf_cidade_chegada " +
           "from voo v, aeronave arnv, aeroporto ac, aeroporto ap, cidade cc, cidade cp where v.cod_aeronave = arnv.cod_aeronave and v.cod_aeroporto_chegada = ac.cod_aeroporto and v.cod_aeroporto_partida = ap.cod_aeroporto and ap.cod_cidade = cp.cod_cidade and ac.cod_cidade = cc.cod_cidade and cod_voo = ?";
        
        String sqlConsultaAeronaves = "select * from aeronave";

        String sqlConsultaAssentosAeronave = "select assentos from aeronave where cod_aeronave = ?";

        String sqlConsultaCidadesDoUf = "select * from cidade where uf = ?";
        String sqlConsultaAeroportosDaCidade = "select * from aeroporto where cod_cidade = ?";
       
        String sqlUpdate = "update voo set nome = ?, valor = ?, data_partida = ?, data_chegada = ?, cod_aeronave = ?, cod_aeroporto_partida = ?, cod_aeroporto_chegada = ? where cod_voo = ?";
        String sqlInsere = "insert into voo (cod_voo, nome, valor, total_assentos, assentos_disponiveis, data_partida, data_chegada, cod_aeronave, cod_aeroporto_partida, cod_aeroporto_chegada) values ((select nvl(max(cod_voo), 0) + 1 from voo), ?, ?, ?, ?, ?, ?, ?, ?, ?)";
       
        

        public FrmCadastroVoo()
        {
            InitializeComponent();
        }

        private void FrmCadastroVoo_Load(object sender, EventArgs e)
        {
            // Estabelece conexão com o bd
            conexao = new OleDbConnection(strConexao);
            conexao.Open();


            //Carrega a relação de aeronaves na combo
            comando = new OleDbCommand(sqlConsultaAeronaves, conexao);
            OleDbDataReader dr = comando.ExecuteReader();

            ArrayList listaAeronaves = new ArrayList();
            while (dr.Read()) {
                listaAeronaves.Add(new {
                    codAeronave = dr["cod_aeronave"],
                    descricao = dr["descricao"]
                });
            }
            // Identifica os membros
            cbAeronave.DisplayMember = "descricao";
            cbAeronave.ValueMember = "codAeronave";
            // Atribui a fonte de dados a combo de aeronaves
            cbAeronave.DataSource = listaAeronaves;

            // Tira a seleção padrão
            cbAeronave.SelectedItem = null;

            if (edicao) { 
                
                // Consulta pelo voo a ser editado
                comando = new OleDbCommand(sqlConsultaVoo, conexao);
                pCod = new OleDbParameter("cod_voo", OleDbType.Integer);
                pCod.Value = codVoo;
                comando.Parameters.Add(pCod);

                dr = comando.ExecuteReader();

                // Popula a interface
                if (dr.Read())
                {
                    txtNome.Text = dr["nome"].ToString();
                    // É preciso adequar o valor à mascara do campo
                    String valorTexto = dr["valor"].ToString();
                    Double valor = Double.Parse(valorTexto);
                    txtValor.Text = String.Format("{0:000000.00}", valor);

                    cbAeronave.SelectedValue = dr["cod_aeronave"];
                    txtAssentosVoo.Text = dr["assentos_disponiveis"].ToString();

                    // desabilita o campo de assentos e a combo de aeronaves quando for edição
                    txtAssentosVoo.Enabled = false;
                    cbAeronave.Enabled = false;

                    // Atribui a quantidade de assentos suportada pela aeronave
                    qntAssentosAeronaveSelecionada = Int32.Parse(dr["total_assentos_aeronave"].ToString());

                    // partida - Seleciona o uf e simula um evento de seleção
                    cbUFOrigem.SelectedItem = dr["uf_cidade_partida"];
                    cbUFOrigem_SelectionChangeCommitted(new Object(), new EventArgs());

                    // partida - Seleciona a cidade e simula um evento de seleção
                    cbCidadeOrigem.SelectedValue = dr["cod_cidade_partida"];
                    cbCidadeOrigem_SelectionChangeCommitted(new Object(), new EventArgs());
                    cbAeroportoOrigem.SelectedValue = dr["cod_aeroporto_partida"];


                    // chegada - Seleciona o uf e simula um evento de seleção
                    cbUFDestino.SelectedItem = dr["uf_cidade_chegada"];
                    cbUFDestino_SelectionChangeCommitted(new Object(), new EventArgs());

                    // chegada - Seleciona a cidade e simula um evento de seleção
                    cbCidadeDestino.SelectedValue = dr["cod_cidade_chegada"];
                    cbCidadeDestino_SelectionChangeCommitted(new Object(), new EventArgs());
                    cbAeroportoDestino.SelectedValue = dr["cod_aeroporto_chegada"];

                    dtpPartida.Value = (DateTime) dr["data_partida"];
                    dtpChegada.Value = (DateTime) dr["data_chegada"];

                }
                else
                {
                    MessageBox.Show("Erro - Edição?");
                    this.Close();
                }
            }


            // Foca o primeiro componente de entrada
            txtNome.Focus();

        }

        private void FrmCadastroVoo_FormClosed(object sender, FormClosedEventArgs e)
        {
            conexao.Close();
        }

        private void cbUFOrigem_SelectionChangeCommitted(object sender, EventArgs e)
        {
            comando = new OleDbCommand(sqlConsultaCidadesDoUf, conexao);

            OleDbParameter pUF = new OleDbParameter("uf", OleDbType.VarChar);
            pUF.Value = cbUFOrigem.SelectedItem;
            comando.Parameters.Add(pUF);

            // Select
            dr = comando.ExecuteReader();
            cbCidadeOrigem.ValueMember = "codCidade";
            cbCidadeOrigem.DisplayMember = "nomeCidade";

            //Popula a combo de cidades de origem de acordo com o uf selecionado  
            if (dr.HasRows)
            {
                ArrayList cidadesOri = new ArrayList();
                while (dr.Read())
                {
                    cidadesOri.Add(new
                    {
                        codCidade = dr["cod_cidade"],
                        nomeCidade = dr["nome"]
                    });
                }
                cbCidadeOrigem.DataSource = cidadesOri;

                // Chama o evento de mudança de seleção da combo de cidade
                // Assim a combo de aeroporto ficará em sincronia
                cbCidadeOrigem_SelectionChangeCommitted(sender, e);
            }
            else
            {
                cbCidadeOrigem.DataSource = null;
                // Inválida a combo de aeroporto para ficar em sincronia
                cbAeroportoOrigem.DataSource = null;
            }



        }

        private void cbCidadeOrigem_SelectionChangeCommitted(object sender, EventArgs e)
        {

            // Busca pelos aeroportos da cidade selecionada e popula a combo de aeroportos de origem
            comando = new OleDbCommand(sqlConsultaAeroportosDaCidade, conexao);

            OleDbParameter pUFOrigem = new OleDbParameter("cod_cidade", OleDbType.Integer);
            pUFOrigem.Value = cbCidadeOrigem.SelectedValue;
            comando.Parameters.Add(pUFOrigem);

            // Select
            dr = comando.ExecuteReader();
            
            // Popula a combo de aeroporto de origem de acordo com a cidade selecionada
            if (dr.HasRows)
            {
                cbAeroportoOrigem.DisplayMember = "descAeroportoOrigem";
                cbAeroportoOrigem.ValueMember = "codAeroportoOrigem";

                ArrayList listaAeroportosOrigem = new ArrayList();
                while (dr.Read())
                {
                    listaAeroportosOrigem.Add(new
                    {
                        descAeroportoOrigem = dr["nome"],
                        codAeroportoOrigem = dr["cod_aeroporto"]
                    });
                }
                cbAeroportoOrigem.DataSource = listaAeroportosOrigem;

            }
            else
            {
                cbAeroportoOrigem.DataSource = null;
            }

        }

        private void cbUFDestino_SelectionChangeCommitted(object sender, EventArgs e)
        {
            comando = new OleDbCommand(sqlConsultaCidadesDoUf, conexao);

            OleDbParameter pUF = new OleDbParameter("uf", OleDbType.VarChar);
            pUF.Value = cbUFDestino.SelectedItem;
            comando.Parameters.Add(pUF);

            // Select
            dr = comando.ExecuteReader();
            cbCidadeDestino.ValueMember = "codCidade";
            cbCidadeDestino.DisplayMember = "nomeCidade";

            //Popula a combo de cidades de destino de acordo com o uf selecionado  
            if (dr.HasRows)
            {
                ArrayList cidadesDest = new ArrayList();
                while (dr.Read())
                {
                    cidadesDest.Add(new
                    {
                        codCidade = dr["cod_cidade"],
                        nomeCidade = dr["nome"]
                    });
                }
                cbCidadeDestino.DataSource = cidadesDest;

                // Chama o evento de mudança de seleção da combo de cidade
                // Assim a combo de aeroporto ficará em sincronia
                cbCidadeDestino_SelectionChangeCommitted(sender, e);
            }
            else
            {
                cbCidadeDestino.DataSource = null;
                // Inválida a combo de aeroporto para ficar em sincronia
                cbAeroportoDestino.DataSource = null;
            }


        }

        private void cbCidadeDestino_SelectionChangeCommitted(object sender, EventArgs e)
        {
            // Busca pelos aeroportos da cidade selecionada e popula a combo de aeroportos de destino
            comando = new OleDbCommand(sqlConsultaAeroportosDaCidade, conexao);

            OleDbParameter pUFDestino = new OleDbParameter("cod_cidade", OleDbType.Integer);
            pUFDestino.Value = cbCidadeDestino.SelectedValue;
            comando.Parameters.Add(pUFDestino);

            // Select
            dr = comando.ExecuteReader();

            // Popula a combo de aeroporto de destino de acordo com a cidade selecionada
            if (dr.HasRows)
            {
                cbAeroportoDestino.DisplayMember = "descAeroportoDest";
                cbAeroportoDestino.ValueMember = "codAeroportoDest";

                ArrayList listaAeroportosDestino = new ArrayList();
                while (dr.Read())
                {
                    listaAeroportosDestino.Add(new
                    {
                        descAeroportoDest = dr["nome"],
                        codAeroportoDest = dr["cod_aeroporto"]
                    });
                }
                cbAeroportoDestino.DataSource = listaAeroportosDestino;

            }
            else
            {
                cbAeroportoDestino.DataSource = null;
            }
        }

        private void btnSalvar_Click(object sender, EventArgs e)
        {

            if (valida())
            {
                if (edicao)
                {
                    // Comando de update
                    comando = new OleDbCommand(sqlUpdate, conexao);

                    pNome = new OleDbParameter("nome", OleDbType.VarChar);
                    pNome.Value = txtNome.Text.Trim();
                    comando.Parameters.Add(pNome);


                    // Atenção especial ao valor
                    // Precisa ser formatado antes de persistir no banco
                    pValor = new OleDbParameter("valor", OleDbType.Double);
                    String valorTexto = txtValor.Text.Trim();
                    String valorParteDecimalTexto = valorTexto.Substring(valorTexto.Length - 2, 2);
                    String valorParteInteiraTexto = valorTexto.Substring(0, valorTexto.Length - 2);
                    double valor = Double.Parse(valorParteInteiraTexto + "," + valorParteDecimalTexto);
                    pValor.Value = valor;
                    comando.Parameters.Add(pValor);

             
                    pDataPartida = new OleDbParameter("data_partida", OleDbType.Date);
                    pDataPartida.Value = dtpPartida.Value;
                    comando.Parameters.Add(pDataPartida);

                    pDataChegada = new OleDbParameter("data_chegada", OleDbType.Date);
                    pDataChegada.Value = dtpChegada.Value;
                    comando.Parameters.Add(pDataChegada);

                    pCodAeronave = new OleDbParameter("cod_aeronave", OleDbType.Integer);
                    pCodAeronave.Value = cbAeronave.SelectedValue;
                    comando.Parameters.Add(pCodAeronave);

                    pCodAeroportoPartida = new OleDbParameter("cod_aeroporto_partida", OleDbType.Integer);
                    pCodAeroportoPartida.Value = cbAeroportoOrigem.SelectedValue;
                    comando.Parameters.Add(pCodAeroportoPartida);

                    pCodAeroportoChegada = new OleDbParameter("cod_aeroporto_chegada", OleDbType.Integer);
                    pCodAeroportoChegada.Value = cbAeroportoDestino.SelectedValue;
                    comando.Parameters.Add(pCodAeroportoChegada);

                    pCod = new OleDbParameter("cod_voo", OleDbType.Integer);
                    pCod.Value = codVoo;
                    comando.Parameters.Add(pCod);

                    // Update
                    comando.ExecuteNonQuery();

                    // Fecha o formulário após a edição
                    this.Close();
                }
                else
                {
                    // Comando de inserção
                    comando = new OleDbCommand(sqlInsere, conexao);

                    pNome = new OleDbParameter("nome", OleDbType.VarChar);
                    pNome.Value = txtNome.Text.Trim();
                    comando.Parameters.Add(pNome);


                    // Atenção especial ao valor
                    // Precisa ser formatado antes de persistir no banco
                    pValor = new OleDbParameter("valor", OleDbType.Double);

                    String valorTexto = txtValor.Text.Trim();
                    String valorParteDecimalTexto = valorTexto.Substring(valorTexto.Length - 2, 2);
                    String valorParteInteiraTexto = valorTexto.Substring(0, valorTexto.Length - 2);
                    double valor = Double.Parse(valorParteInteiraTexto + "," + valorParteDecimalTexto);
                    pValor.Value = valor;
                    comando.Parameters.Add(pValor);

                    // Atribui o valor de assentos(disponveis) ao total_assentos
                    // para efeito de registro, pois a coluna assentos_disponiveis será decrementada a cada venda realizada
                    pTotalAssentos = new OleDbParameter("total_assentos", OleDbType.Integer);
                    pTotalAssentos.Value = txtAssentosVoo.Text.Trim();
                    comando.Parameters.Add(pTotalAssentos);

                    pAssentos = new OleDbParameter("assentos_disponiveis", OleDbType.Integer);
                    pAssentos.Value = txtAssentosVoo.Text.Trim();
                    comando.Parameters.Add(pAssentos);

                    pDataPartida = new OleDbParameter("data_partida", OleDbType.Date);
                    pDataPartida.Value = dtpPartida.Value;
                    comando.Parameters.Add(pDataPartida);

                    pDataChegada = new OleDbParameter("data_chegada", OleDbType.Date);
                    pDataChegada.Value = dtpChegada.Value;
                    comando.Parameters.Add(pDataChegada);

                    pCodAeronave = new OleDbParameter("cod_aeronave", OleDbType.Integer);
                    pCodAeronave.Value = cbAeronave.SelectedValue;
                    comando.Parameters.Add(pCodAeronave);

                    pCodAeroportoPartida = new OleDbParameter("cod_aeroporto_partida", OleDbType.Integer);
                    pCodAeroportoPartida.Value = cbAeroportoOrigem.SelectedValue;
                    comando.Parameters.Add(pCodAeroportoPartida);

                    pCodAeroportoChegada = new OleDbParameter("cod_aeroporto_chegada", OleDbType.Integer);
                    pCodAeroportoChegada.Value = cbAeroportoDestino.SelectedValue;
                    comando.Parameters.Add(pCodAeroportoChegada);

                    // Insert
                    comando.ExecuteNonQuery();


                    // Verifica se o usuário deseja inserir um novo registro
                    DialogResult resultado = MessageBox.Show(this,
                                                           "Cadastrado com sucesso.\nDeseja cadastrar outro registro?",
                                                           "Cadastro",
                                                            MessageBoxButtons.YesNo);

                    if (resultado == DialogResult.Yes)
                    {
                        // Limpa os campos
                        txtNome.Clear();
                        txtValor.Clear();
                        cbAeronave.SelectedItem = null;
                        cbUFOrigem.SelectedItem = null;
                        cbCidadeOrigem.SelectedItem = null;
                        cbAeroportoOrigem.SelectedItem = null;
                        cbUFDestino.SelectedItem = null;
                        cbCidadeDestino.SelectedItem = null;
                        cbAeroportoDestino.SelectedItem = null;
                        dtpPartida.Value = DateTime.Now;
                        dtpChegada.Value = DateTime.Now;
                    }
                    else
                    {
                        this.Close();
                    }

                }

               
            }

        }

        private bool valida()
        {
            
            // Nome
            String nome = txtNome.Text.Trim();
            if (nome.Length < 5 || nome.Length > 100)
            {
                MessageBox.Show(this, "Preencha os campos corretamente.", "Validação", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                txtNome.Focus();
                txtNome.BackColor = Color.Tomato;
                return false;
            }
            else
                txtNome.BackColor = Color.White;

            // Valor
            String valorTexto = txtValor.Text;
            int valor = 0;
            try
            {
            valor = Int32.Parse(valorTexto);
            }
            catch (Exception)
            {
            }

            if (valor < 10)
            {
                MessageBox.Show(this, "Preencha os campos corretamente.", "Validação", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                txtValor.Focus();
                txtValor.BackColor = Color.Tomato;
                return false;
            }
            else
                txtValor.BackColor = Color.White;

            // Aeronave
            if (cbAeronave.SelectedItem == null)
            {
                MessageBox.Show(this, "Preencha os campos corretamente.", "Validação", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                cbAeronave.DroppedDown = true;
                return false;
            }

            // Assentos disponíveis
            String assentosTexto = txtAssentosVoo.Text.Trim();
            int assentos = 0;
            try
            {
              assentos = Int32.Parse(assentosTexto);
            }
            catch (Exception)
            {
                MessageBox.Show(this, "Preencha os campos corretamente.", "Validação", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                txtAssentosVoo.Focus();
                txtAssentosVoo.BackColor = Color.Tomato;
                return false;
            }

            if (assentos < 0)
            {
                MessageBox.Show(this, "Preencha os campos corretamente.", "Validação", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                txtAssentosVoo.Focus();
                txtAssentosVoo.BackColor = Color.Tomato;
                return false;
            }
            else
                txtAssentosVoo.BackColor = Color.White;


            if (assentos > qntAssentosAeronaveSelecionada) 
            {
                MessageBox.Show(this, "Não é possível atribuir uma quantidade de assentos maior que a permitida pela aeronave.\nMáximo: "
                    + qntAssentosAeronaveSelecionada + ".", "Validação", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                txtAssentosVoo.Focus();
                txtAssentosVoo.BackColor = Color.Tomato;
                return false;
            }
            else
                txtAssentosVoo.BackColor = Color.White;

            // Origem

            if (cbUFOrigem.SelectedItem == null)
            {
                MessageBox.Show(this, "Preencha os campos corretamente.", "Validação", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                cbUFOrigem.DroppedDown = true;
                return false;
            }

            if (cbCidadeOrigem.SelectedItem == null)
            {
                MessageBox.Show(this, "Preencha os campos corretamente.", "Validação", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                cbCidadeOrigem.DroppedDown = true;
                return false;
            }

            if (cbAeroportoOrigem.SelectedItem == null)
            {
                MessageBox.Show(this, "Preencha os campos corretamente.", "Validação", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                cbAeroportoOrigem.DroppedDown = true;
                return false;
            }

            // Destino

            if (cbUFDestino.SelectedItem == null)
            {
                MessageBox.Show(this, "Preencha os campos corretamente.", "Validação", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                cbUFDestino.DroppedDown = true;
                return false;
            }

            if (cbCidadeDestino.SelectedItem == null)
            {
                MessageBox.Show(this, "Preencha os campos corretamente.", "Validação", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                cbCidadeDestino.DroppedDown = true;
                return false;
            }

            if (cbAeroportoDestino.SelectedItem == null)
            {
                MessageBox.Show(this, "Preencha os campos corretamente.", "Validação", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                cbAeroportoDestino.DroppedDown = true;
                return false;
            }



            // Aeroportos
            if (cbAeroportoOrigem.SelectedValue.Equals(cbAeroportoDestino.SelectedValue))
            {
                MessageBox.Show(this, "Preencha os campos corretamente.", "Validação", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                cbAeroportoOrigem.DroppedDown = true;
                return false;
            }


            // Validação dos horários

            // Os horários não podem ser iguais
            DateTime dataPartida = dtpPartida.Value;
            DateTime dataChegada = dtpChegada.Value;



            // retorno = 0 : mesma data
            // retorno < 0 : data menor
            if (dataChegada.CompareTo(dataPartida) <= 0) 
            {
                MessageBox.Show(this, "Preencha os horários corretamente.", "Validação", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return false;
            }

           
            // Se chegar até aqui validou
            return true;
        }

        private void cbAeronave_SelectionChangeCommitted(object sender, EventArgs e)
        {
            comando = new OleDbCommand(sqlConsultaAssentosAeronave, conexao);
            
            OleDbParameter pCodAeronave = new OleDbParameter("cod_aeronave", OleDbType.Integer);
            pCodAeronave.Value = cbAeronave.SelectedValue;
            comando.Parameters.Add(pCodAeronave);

            // Select
            dr = comando.ExecuteReader();

            // Sugere inicialmente a quantidade de assentos da aeronave
            if (dr.Read())
            {
                txtAssentosVoo.Text = dr["assentos"].ToString();
                // Armazena a quantidade total de assentos da aeronave (para efeito de validação posteriormente)
                qntAssentosAeronaveSelecionada = Int32.Parse(dr["assentos"].ToString());
            }

        }

        private void FrmCadastroVoo_KeyDown(object sender, KeyEventArgs e)
        {
            //Hotkey para salvar os dados
            if (e.KeyData == (Keys.Control | Keys.S))
            {
                btnSalvar_Click(sender, e);
            }

            //Hotkey para a tecla ESC fechar a janela
            if (e.KeyData == (Keys.Escape))
            {
                this.Close();
            }
        }    
    }
}
